package br.ufrj.dcc.ad.simulador;

import br.ufrj.dcc.ad.cliente.Cliente;
import br.ufrj.dcc.ad.criterioParada.CriterioDeParada;
import br.ufrj.dcc.ad.gerador.GeradorTempoEventos;
import br.ufrj.dcc.ad.gerador.GeradorTempoEventosExponencial;
import br.ufrj.dcc.ad.servidor.Servidor;
import br.ufrj.dcc.ad.servidor.ServidorOnOff;

public class SimuladorMG1 extends Simulador{
	private GeradorTempoEventos geradorServico;
	private GeradorTempoEventos geradorChegadas;
	int idCliente;
	
	
	public SimuladorMG1(CriterioDeParada criterioDeParada, Servidor servidor, GeradorTempoEventos geradorServico, double lambda) {
		super(criterioDeParada, servidor);
		this.geradorChegadas = new GeradorTempoEventosExponencial(lambda);
		this.geradorServico = geradorServico;
		this.idCliente = 0;
	}
	
	@Override
	protected Cliente geraCliente() {
		double instanteChegada = (this.tempoDecorridoDesdeInicioSimulacao += this.geradorChegadas.getTempoEntreEventos());
		double tempoServico = this.geradorServico.getTempoEntreEventos();
		return new Cliente(this.idCliente++, instanteChegada, tempoServico);
	}

	@Override
	protected void trataCliente(Cliente cliente) {
		if (clientesAtendidos.size() == 0) {
			double instanteChegada = cliente.getInstanteChegada();
			cliente.setTempoServico(cliente.getTempoServico() + this.servidor.getTempoSetup());
			cliente.setInstanteInicioServico(instanteChegada);
			cliente.setInstanteFimServico(instanteChegada + cliente.getTempoServico());
			cliente.setTempoEspera(0);
		} else {
			Cliente ultimoClienteAtendido = clientesAtendidos.get(clientesAtendidos.size() - 1);
			
			double tempoEspera;
			if(ultimoClienteAtendido.getInstanteFimServico() - cliente.getInstanteChegada() > 0.0){
				tempoEspera = ultimoClienteAtendido.getInstanteFimServico() - cliente.getInstanteChegada();
				cliente.setInstanteInicioServico(cliente.getInstanteChegada() + tempoEspera);
			}
			else{
				tempoEspera = 0.0;
				cliente.setInstanteInicioServico(cliente.getInstanteChegada());
				
				this.servidor.adicionaPeriodoOcioso(Math.abs(ultimoClienteAtendido.getInstanteFimServico() - cliente.getInstanteInicioServico()));
				cliente.setTempoServico(cliente.getTempoServico() + this.servidor.getTempoSetup());
			}
			
			double instanteChegada = cliente.getInstanteChegada();
			cliente.setInstanteFimServico(instanteChegada + tempoEspera + cliente.getTempoServico());
			cliente.setTempoEspera(tempoEspera);
		}
		
		this.servidor.adicionaPeriodoOcupado(cliente.getTempoServico());
		clientesAtendidos.add(cliente);
	}
	

	public GeradorTempoEventos getGeradorServico() {
		return geradorServico;
	}

	public void setGeradorServico(GeradorTempoEventos geradorServico) {
		this.geradorServico = geradorServico;
	}

	public Servidor getServidor() {
		return servidor;
	}
	
	
	
	
}
